﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using System.Windows.Controls;
using SHomeWorkshop.LunarConcept.Tools;
using System.Reflection;
using System.Windows.Media;
using System.Windows;
using SHomeWorkshop.LunarConcept.Adorners;
using System.Windows.Documents;
using System.ComponentModel;
using SHomeWorkshop.LunarConcept.Enums;
using System.Windows.Input;
using System.Windows.Data;
using System.Windows.Media.Effects;
using SHomeWorkshop.LunarMind;

namespace SHomeWorkshop.LunarConcept.Widgets
{
    /// <summary>
    /// 创建时间：2011年12月26日
    /// 创建者：  杨震宇
    /// 修改时间：2012年1月19日
    /// 修改内容：将TextArea的主要功能全部移植到此类中，以便所有Widget均支持文本。
    /// 
    /// 主要用途：所有部件类的基类，用以派生其它具体部件类。
    /// </summary>
    public abstract class Widget : AdornerDecorator, INotifyPropertyChanged
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [构造方法]生成一个Widget。
        /// </summary>
        /// <param name="masterPageEditor"></param>
        public Widget(PageEditorReader masterPageEditor)
        {
            this.Focusable = true;

            this.NewID();
            this.masterEditor = masterPageEditor;

            //自动绑定最大宽度为页面横边减２００.
            Binding maxWidthBinding = new Binding("Width");
            maxWidthBinding.Source = masterEditor;
            maxWidthBinding.Converter = Widget.MaxWidthConverter;
            this.SetBinding(Widget.MaxWidthProperty, maxWidthBinding);

            this.textHideAdorner = new TextHidedAdorner(this.mainTextPanel) { Visibility = Visibility.Collapsed };//默认不显示。
            this.AdornerLayer.Add(this.textHideAdorner);

            this.mainTextPanel.SizeChanged += new SizeChangedEventHandler(mainTextPanel_SizeChanged);
        }

        protected void hyperLinkAdorner_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            try
            {
                System.Diagnostics.Process.Start("iexplore.exe", $"\"{this.hyperLinkText}\"");
            }
            catch (Exception ex)
            {
                MessageBox.Show("　　无法打开指定的网址。异常信息如下：\r\n" + ex.Message, Globals.AppName,
                     MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        #endregion

        #region 字段与属性===================================================================================================

        private string autoNumberString = string.Empty;
        /// <summary>
        /// [读写]与后台Xml数据无关。只有TitleLevel为T1-T5才有效。
        /// 这个值应由EditorManager来刷新。本身没有意义。在EditorManager刷新后，会出现在第一行文本开头。
        /// </summary>
        public string AutoNumberString
        {
            get
            {
                switch (this.titleLevel)
                {
                    case TitleStyle.T1:
                    case TitleStyle.T2:
                    case TitleStyle.T3:
                    case TitleStyle.T4:
                    case TitleStyle.T5: return this.autoNumberString;
                    default: return string.Empty;
                }
            }
            set
            {
                autoNumberString = value;
                this.RefreshText();
            }
        }

        private string commentText = string.Empty;
        /// <summary>
        /// [读写]备注文本。
        /// </summary>
        [Tools.LunarProperty("CommentText", PropertyDateType.String)]
        public string CommentText
        {
            get { return commentText; }
            set
            {
                this.commentText = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.CommentTextTag, value);
                }
                this.RefreshCommentText();
            }
        }


        /// <summary>
        /// 用于显示备注的装饰器。
        /// </summary>
        protected CommentAdorner commentAdorner;

        protected HyperLinkAdorner hyperLinkAdorner;

        private string hyperLinkText = string.Empty;
        /// <summary>
        /// [读写]超链接文本。
        /// </summary>
        [Tools.LunarProperty("HyperLinkText", PropertyDateType.String)]
        public string HyperLinkText
        {
            get { return hyperLinkText; }
            set
            {
                hyperLinkText = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.HyperLinkTextTag, value);
                }
                this.RefreshHyperLinkText();
            }
        }

        protected string widgetClassLocalName;
        /// <summary>
        /// [只读]返回内部定义的中文类型名。
        /// </summary>
        public string WidgetClassLocalName
        {
            get { return widgetClassLocalName; }
        }

        protected Enums.WidgetTypes widgetType = WidgetTypes.None;
        /// <summary>
        /// [只读]部件类型名。
        /// </summary>
        public Enums.WidgetTypes WidgetType
        {
            get { return widgetType; }
        }

        /// <summary>
        /// [只读]返回右下角坐标。
        /// </summary>
        public abstract Point BottomRight { get; }

        /// <summary>
        /// [只读]中心点坐标。
        /// </summary>
        public Point Center
        {
            get
            {
                Point topLeft = this.TopLeft;
                Point bottomRight = this.BottomRight;
                return new Point(topLeft.X + (bottomRight.X - topLeft.X) / 2,
                    topLeft.Y + (bottomRight.Y - topLeft.Y) / 2);
            }
        }

        /// <summary>
        /// [只读]返回此部件的【真实】类的名称。
        /// ——此属性不应override，因为完全没有必要。
        /// </summary>
        public string ClassName
        {
            get
            {
                return this.GetType().Name;
            }
        }

        /// <summary>
        /// [只读]ClassName的别称。
        /// </summary>
        public string WidgetClassName
        {
            get { return this.ClassName; }
        }

        private static readonly Point defaultRenderCenter = new Point(0.5, 0.5);
        /// <summary>
        /// 用于旋转文本区的中心定位点坐标。
        /// </summary>
        public static Point DefaultRenderCenter
        {
            get { return Widget.defaultRenderCenter; }
        }

        private static readonly RotateTransform defaultRotateTransform = new RotateTransform(0);
        /// <summary>
        /// 默认不旋转文本区。
        /// </summary>
        public static RotateTransform DefaultRotateTransform
        {
            get { return Widget.defaultRotateTransform; }
        }

        private static Thickness defaultPadding = new Thickness(2);
        /// <summary>
        /// [静态只读]默认的内部间隙宽。
        /// </summary>
        public static Thickness DefaultPadding { get { return defaultPadding; } }

        #region 两种默认字体。

        private static FontFamily font_SimSun = new FontFamily("SimSun");

        private static FontFamily font_MicrosoftYaHei = new FontFamily("Microsoft YaHei");

        #endregion

        private bool fillBlankMode = true;//默认开启
        /// <summary>
        /// [读写]填空模式。
        /// </summary>
        [Tools.LunarProperty("FillBlankMode", PropertyDateType.Bool)]
        public bool FillBlankMode
        {
            get { return fillBlankMode; }
            set
            {
                fillBlankMode = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.FillBlankModeTag, value.ToString());
                }
                this.RefreshText();
            }
        }

        /// <summary>
        /// [静态字段]上下标字号绑定的转换器。
        /// </summary>
        private static Converters.HalfTextSizeConverter halfTextSizeConverter = new Converters.HalfTextSizeConverter();

        /// <summary>
        /// 返回部件文本（去除Xml格式标签后的文本）。
        /// </summary>
        public string Text
        {
            get
            {
                if (this.xmlData == null) return null;
                XmlNode paragraphSetNode = this.ParagraphSetNode;
                if (paragraphSetNode != null)
                {
                    StringBuilder sb = new StringBuilder();

                    XmlNodeList paragraphNodeList = paragraphSetNode.SelectNodes(XmlTags.ParagraphTag);

                    if (paragraphNodeList != null && paragraphNodeList.Count > 0)
                    {
                        foreach (XmlNode paragrathNode in paragraphNodeList)
                        {
                            XmlNodeList textNodeList = paragrathNode.SelectNodes(XmlTags.TextTag);
                            if (textNodeList == null || textNodeList.Count <= 0) continue;

                            foreach (XmlNode textNode in textNodeList)
                            {
                                sb.Append(textNode.InnerText);
                            }
                        }
                    }

                    return this.AutoNumberString + sb.ToString();
                }
                else return string.Empty;
            }
        }

        /// <summary>
        /// 隐藏文本时显示的装饰器，避免用户看不到文本时不知所措。
        /// </summary>
        protected TextHidedAdorner textHideAdorner;

        protected string id;
        /// <summary>
        /// [只读]部件的唯一标识符。应使用Guid字符串。
        /// ——万一需要更改此值，请使用NewID()方法。
        /// </summary>
        [LunarConcept.Tools.LunarProperty("Id", Enums.PropertyDateType.String)]
        public string Id
        {
            get { return id; }
        }

        protected bool isShadowVisible = false;
        /// <summary>
        /// [读写]是否显示阴影。
        /// </summary>
        [Tools.LunarProperty("IsShadowVisible", PropertyDateType.Bool)]
        public bool IsShadowVisible
        {
            get { return isShadowVisible; }
            set
            {
                isShadowVisible = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.IsShadowVisibleTag, value.ToString());
                }

                RefreshIsShadowVisible();
            }
        }

        /// <summary>
        /// 判断是否设置了指定属性的自有值。
        /// </summary>
        public bool IsWidgetPropertySetted(string propertyName)
        {
            if (this.xmlData == null) return false;
            XmlAttribute attr = this.xmlData.GetAttribute(propertyName);
            if (attr == null || string.IsNullOrEmpty(attr.Value)) return false;

            return true;
        }

        private bool isTextVisible = true;
        /// <summary>
        /// [读写]部件文本是否可见。默认为true。
        /// </summary>
        [Tools.LunarProperty("IsTextVisible", PropertyDateType.Bool)]
        public bool IsTextVisible
        {
            get { return isTextVisible; }
            set
            {
                isTextVisible = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.IsTextVisibleTag, isTextVisible.ToString());
                }

                this.RefreshIsTextVisible();
            }
        }

        protected WidgetLayerIndex layerIndex = WidgetLayerIndex.ContentWidget;
        /// <summary>
        /// [读写]在页面中的层次。
        /// </summary>
        [Tools.LunarProperty("LayerIndex", PropertyDateType.LayerIndex)]
        public WidgetLayerIndex LayerIndex
        {
            get { return layerIndex; }
            set
            {
                this.layerIndex = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.LayerIndexTag, value.ToString());
                }
                this.RefreshLayerIndex();
            }
        }

        protected bool isLocked = false;
        /// <summary>
        /// [读写]设置部件是否处于被锁定状态。
        /// 被锁定的部件将不能移动，也不能拖动控制点（如果存在）。
        /// </summary>
        [Tools.LunarProperty("IsLocked", PropertyDateType.Bool)]
        public virtual bool IsLocked
        {
            get { return isLocked; }
            set
            {
                isLocked = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.IsLockedTag, value.ToString());
                }

            }
        }

        /// <summary>
        /// 用以承载简单富格式文本的TextBlock。
        /// </summary>
        protected StackPanel mainTextPanel = new StackPanel()
        {
            Margin = DefaultPadding,
            HorizontalAlignment = HorizontalAlignment.Center,
        };

        protected PageEditorReader masterEditor;
        /// <summary>
        /// [只读]此部件所在的编辑器。
        /// ——不允许转移编辑器，因为粘贴操作是从文本转换的，会生成一个新的部件。
        /// </summary>
        public PageEditorReader MasterEditor
        {
            get { return masterEditor; }
        }

        private static Converters.TextMaxWidthConverter maxWidthConverter = new Converters.TextMaxWidthConverter();
        /// <summary>
        /// [只读]最大宽度绑定所需要的转换器。
        /// </summary>
        public static Converters.TextMaxWidthConverter MaxWidthConverter
        {
            get { return Widget.maxWidthConverter; }
        }

        /// <summary>
        /// [只读]返回外虚拟边框。（实有边框四边向向外扩展20。）
        /// </summary>
        public abstract Rect OuterRect { get; }

        /// <summary>
        /// [只读]返回“ParagraphSet”节点。
        /// </summary>
        public XmlNode ParagraphSetNode
        {
            get
            {
                if (this.xmlData == null) return null;

                XmlNode paragraphSetNode = this.xmlData.SelectSingleNode(XmlTags.ParagraphSetTag);
                if (paragraphSetNode == null)
                {
                    paragraphSetNode = this.xmlData.AppendXmlAsChild("<" + XmlTags.ParagraphSetTag + " />");
                }

                return paragraphSetNode;
            }
        }

        /// <summary>
        /// [只读]由TopLeft和BottomRight构成的矩形。
        /// </summary>
        public Rect RealRect
        {
            get { return new Rect(TopLeft, BottomRight); }
        }

        private static DropShadowEffect shadowEffect = new DropShadowEffect()
        {
            BlurRadius = 10,
            Color = Colors.Black,
        };

        /// <summary>
        /// [只读]部件阴影效果。
        /// </summary>
        public static DropShadowEffect ShadowEffect
        {
            get { return Widget.shadowEffect; }
        }

        /// <summary>
        /// [只读]取当前文本块的位置。
        /// </summary>
        public Point TextPanelLocation
        {
            get
            {
                //this.mainTextPanel.InvalidateArrange();
                //this.mainTextPanel.UpdateLayout();
                return new Point(Canvas.GetLeft(this.mainTextPanel), Canvas.GetTop(this.mainTextPanel));
            }
        }

        private Enums.TitleStyle titleLevel = TitleStyle.Normal;
        /// <summary>
        /// [读写]标题层级。一般部件只涉及自动编号、字形、字号。矩形涉及缩进应重写本属性的刷新方法。
        /// </summary>
        [Tools.LunarProperty("TitleLevel", PropertyDateType.TitleStyle)]
        public Enums.TitleStyle TitleLevel
        {
            get { return titleLevel; }
            set
            {
                titleLevel = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.TitleLevelTag, value.ToString());
                }

                this.RefreshText();
            }
        }

        /// <summary>
        /// 提示用户如何开始编辑文本。
        /// </summary>
        private static string tooltipText = "编辑文本：Enter（或双击）";

        /// <summary>
        /// [只读]左上角坐标。
        /// </summary>
        public abstract Point TopLeft { get; }

        protected Brush widgetBackColor = Brushes.Transparent;
        /// <summary>
        /// 部件背景色。默认为透明色。
        /// </summary>
        [Tools.LunarProperty("WidgetBackColor", PropertyDateType.Brush)]
        public Brush WidgetBackColor
        {
            get { return widgetBackColor; }
            set
            {
                widgetBackColor = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.WidgetBackColor,
                        BrushManager.GetEnglishName(value));
                }
                this.RefreshWidgetBackColor();
            }
        }

        protected Brush widgetForeColor = Brushes.Black;
        /// <summary>
        /// 部件前景色。默认为黑色。
        /// </summary>
        [Tools.LunarProperty("WidgetForeColor", PropertyDateType.Brush)]
        public virtual Brush WidgetForeColor
        {
            get { return widgetForeColor; }
            set
            {
                widgetForeColor = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.WidgetForeColor,
                        BrushManager.GetEnglishName(value));
                }
                this.RefreshWidgetForeColor();
            }
        }

        protected Brush widgetLineColor = Brushes.Black;
        /// <summary>
        /// 部件前景色。默认为黑色。
        /// </summary>
        [Tools.LunarProperty("WidgetLineColor", PropertyDateType.Brush)]
        public virtual Brush WidgetLineColor
        {
            get { return widgetLineColor; }
            set
            {
                widgetLineColor = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.WidgetLineColorTag,
                        BrushManager.GetEnglishName(value));
                }
                this.RefreshWidgetLineColor();
            }
        }

        protected double widgetLineWidth = 1;
        /// <summary>
        /// [读写]线宽。
        /// </summary>
        [Tools.LunarProperty("WidgetLineWidth", PropertyDateType.Double)]
        public virtual double WidgetLineWidth
        {
            get { return widgetLineWidth; }
            set
            {
                widgetLineWidth = value;
                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.WidgetLineWidthTag, widgetLineWidth.ToString());
                }

                RefreshWidgetLineWidth();
            }
        }

        protected double widgetOpacity = 1.0;
        /// <summary>
        /// [读写]部件透明度。
        /// </summary>
        [Tools.LunarProperty("WidgetOpacity", PropertyDateType.Double)]
        public double WidgetOpacity
        {
            get { return widgetOpacity; }
            set
            {
                if (value < 0.1)
                {
                    widgetOpacity = 0.1;//最小
                }
                else if (value > 1)
                {
                    widgetOpacity = 1;
                }
                else
                {
                    widgetOpacity = value;
                }

                if (this.xmlData != null)
                {
                    this.xmlData.SetAttribute(XmlTags.WidgetOpacityTag, widgetOpacity.ToString());
                }

                this.RefreshWidgetOpacity();
            }
        }

        /// <summary>
        /// 刷新透明度。
        /// </summary>
        public void RefreshWidgetOpacity()
        {
            this.Opacity = this.widgetOpacity;
        }

        protected XmlNode xmlData;
        /// <summary>
        /// 后台Xml数据节点。set时会调用Build()方法重建部件内容。
        /// </summary>
        [LunarProperty("XmlData", Enums.PropertyDateType.OutXmlText)]
        public XmlNode XmlData
        {
            get { return xmlData; }
            set
            {
                xmlData = value;
                Build();
            }
        }

        /// <summary>
        /// [只写]这个属性本是为SetProperty()方法提供的。
        /// 设置此属性值会更新XmlData的内容，从而调用Build()方法。
        /// </summary>
        [LunarConcept.Tools.LunarProperty("XmlDataInnerXml", Enums.PropertyDateType.ParagraphSetInnerXmlText)]
        public string XmlDataInnerXml
        {
            set
            {
                XmlNode paragraphSetNode = this.ParagraphSetNode;
                if (paragraphSetNode != null)
                {
                    paragraphSetNode.InnerXml = value;
                }
                RefreshText();
            }
        }


        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 根据xmlData节点的内容重建部件内容。
        /// 注意，实现类必须在Build末尾调用:
        /// this.RefreshText();
        /// </summary>
        public virtual void Build()
        {
            if (this.xmlData == null) return;

            XmlAttribute attrId = this.xmlData.GetAttribute(XmlTags.IdTag);
            if (attrId != null)
            {
                this.id = attrId.Value;
            }
            else
            {
                this.NewID();
            }

            XmlAttribute attrAutoNumberText = this.xmlData.GetAttribute(XmlTags.AutoNumberTextTag);
            if (attrAutoNumberText != null)
            {
                this.AutoNumberString = attrAutoNumberText.Value;
            }

            //取锁定状态。
            XmlAttribute attrIsLocked = this.xmlData.GetAttribute(XmlTags.IsLockedTag);
            if (attrIsLocked != null)
            {
                this.isLocked = bool.Parse(attrIsLocked.Value);
            }
            else
            {
                this.isLocked = false;
            }

            XmlAttribute attrLayerIndex = this.xmlData.GetAttribute(XmlTags.LayerIndexTag);
            if (attrLayerIndex != null)
            {
                this.layerIndex = (WidgetLayerIndex)Enum.Parse(typeof(WidgetLayerIndex), attrLayerIndex.Value);
            }
            else
            {
                this.layerIndex = WidgetLayerIndex.ContentWidget;//默认值
            }

            XmlAttribute attrTitleLevel = this.xmlData.GetAttribute(XmlTags.TitleLevelTag);
            if (attrTitleLevel != null)
            {
                this.titleLevel = (Enums.TitleStyle)Enum.Parse(typeof(Enums.TitleStyle), attrTitleLevel.Value);
            }
            else
            {
                this.titleLevel = TitleStyle.Normal;
            }

            XmlAttribute attrIsTextVisible = this.xmlData.GetAttribute(XmlTags.IsTextVisibleTag);
            if (attrIsTextVisible != null)
            {
                this.isTextVisible = bool.Parse(attrIsTextVisible.Value);
            }
            else
            {
                this.isTextVisible = true;
            }

            XmlAttribute attrCommentText = this.xmlData.GetAttribute(XmlTags.CommentTextTag);
            if (attrCommentText != null)
            {
                this.commentText = attrCommentText.Value;
            }
            else
            {
                this.commentText = string.Empty;
            }

            XmlAttribute attrHyperLinkText = this.xmlData.GetAttribute(XmlTags.HyperLinkTextTag);
            if (attrHyperLinkText != null)
            {
                this.hyperLinkText = attrHyperLinkText.Value;
            }
            else
            {
                this.hyperLinkText = string.Empty;
            }

            XmlAttribute attrWidgetForeground = this.xmlData.GetAttribute(XmlTags.WidgetForeColor);
            if (attrWidgetForeground != null)
            {
                this.WidgetForeColor = BrushManager.GetBrush(attrWidgetForeground.Value);
            }

            XmlAttribute attrWidgetBackground = this.xmlData.GetAttribute(XmlTags.WidgetBackColor);
            if (attrWidgetBackground != null)
            {
                this.WidgetBackColor = BrushManager.GetBrush(attrWidgetBackground.Value);
            }

            XmlAttribute attrWidgetLineWidth = this.xmlData.GetAttribute(XmlTags.WidgetLineWidthTag);
            if (attrWidgetLineWidth != null)
            {
                this.widgetLineWidth = double.Parse(attrWidgetLineWidth.Value);
            }

            XmlAttribute attrWidgetLineColor = this.xmlData.GetAttribute(XmlTags.WidgetLineColorTag);
            if (attrWidgetLineColor != null)
            {
                this.WidgetLineColor = BrushManager.GetBrush(attrWidgetLineColor.Value);
            }

            XmlAttribute attrOpecity = this.xmlData.GetAttribute(XmlTags.WidgetOpacityTag);
            if (attrOpecity != null)
            {
                this.WidgetOpacity = double.Parse(attrOpecity.Value);
            }

            XmlAttribute attrIsShadowVisible = this.xmlData.GetAttribute(XmlTags.IsShadowVisibleTag);
            if (attrIsShadowVisible != null)
            {
                this.IsShadowVisible = bool.Parse(attrIsShadowVisible.Value);
            }

            XmlAttribute attrFillBlankMode = this.xmlData.GetAttribute(XmlTags.FillBlankModeTag);
            if (attrFillBlankMode != null)
            {
                this.FillBlankMode = bool.Parse(attrFillBlankMode.Value);
            }

            //下面这四个在本类就已经是“最终实现”。因此直接调用。
            this.RefreshText();
            this.RefreshLayerIndex();
            this.RefreshIsTextVisible();

            //与样式无关。
            this.RefreshCommentText();
            this.RefreshHyperLinkText();

            //对于与WidgetStyle相关的属性的刷新，看此类是否已是“最终实现类”即可决定。
            this.RefreshWidgetForeColor();
            this.RefreshIsShadowVisible();
            this.RefreshWidgetOpacity();
        }

        /// <summary>
        /// 生成某个段落中的某个文本片段。
        /// </summary>
        private void BuildAndAppendOneSpan(TextBlock textBlock, XmlNode textNode)
        {
            Span span = new Span();
            span.Inlines.Add(new Run(XmlTools.RestoreXmlChars(textNode.InnerXml)));

            //取文本特性

            XmlAttribute attrTextAlignment = textNode.GetAttribute("TextAlignment");
            if (attrTextAlignment != null)
            {
                textBlock.TextAlignment = (TextAlignment)Enum.Parse(typeof(TextAlignment), attrTextAlignment.Value);
            }

            XmlAttribute attrForeground = textNode.GetAttribute("ForeColor");
            if (attrForeground != null)
            {
                Brush foreground = BrushManager.GetBrushByEnglishName(attrForeground.Value);
                if (foreground != null)
                    span.Foreground = foreground;
            }
            //为便于刷新前景色。必须去掉——让它们与TextBlock保持一致。
            //else
            //{
            //    span.Foreground = this.widgetForeColor;
            //}

            XmlAttribute attrBackground = textNode.GetAttribute("BackColor");
            if (attrBackground != null)
            {
                Brush background = BrushManager.GetBrushByEnglishName(attrBackground.Value);
                if (background != null)
                    span.Background = background;
            }
            else
            {
                span.Background = Brushes.Transparent;
            }

            XmlAttribute attrFontSize = textNode.GetAttribute("FontSize");
            if (attrFontSize != null)
            {
                span.FontSize = double.Parse(attrFontSize.Value);
            }
            else
            {
                span.FontSize = Globals.MainWindow.DefaultFontSize;
            }

            XmlAttribute attrFontWeight = textNode.GetAttribute("FontWeight");
            if (attrFontWeight != null && attrFontWeight.Value == "Bold")
            {
                span.FontWeight = FontWeights.Bold;
            }

            XmlAttribute attrFontStyle = textNode.GetAttribute("FontStyle");
            if (attrFontStyle != null && attrFontStyle.Value == "Italic")
            {
                span.FontStyle = FontStyles.Italic;
            }

            XmlAttribute attrUnderLine = textNode.GetAttribute("UnderLine");
            if (attrUnderLine != null && attrUnderLine.Value == "True")
            {
                span.TextDecorations.Add(TextDecorations.Underline);
            }

            XmlAttribute attrStrikeLine = textNode.GetAttribute("StrikeLine");
            if (attrStrikeLine != null && attrStrikeLine.Value == "True")
            {
                span.TextDecorations.Add(TextDecorations.Strikethrough);
            }

            XmlAttribute attrFontName = textNode.GetAttribute("FontName");
            if (attrFontName != null)
            {
                FontFamily fontFamily = new FontFamily(attrFontName.Value);
                if (fontFamily != null)
                    span.FontFamily = fontFamily;
            }
            else
            {
                if (span.FontSize > 15)
                {
                    span.FontFamily = font_MicrosoftYaHei;
                }
                else
                {
                    span.FontFamily = font_SimSun;
                }
            }

            XmlAttribute attrBaseLineAlignment = textNode.GetAttribute("BaseLineAlignment");
            if (attrBaseLineAlignment != null)
            {
                switch (attrBaseLineAlignment.Value)
                {
                    case "Top":
                        {
                            span.BaselineAlignment = BaselineAlignment.Top;

                            Binding fontSizeBinding = new Binding("DefaultFontSize");
                            fontSizeBinding.Source = Globals.MainWindow.DefaultFontSize;
                            fontSizeBinding.Converter = halfTextSizeConverter;

                            span.SetBinding(Span.FontSizeProperty, fontSizeBinding);
                            break;
                        }
                    case "Bottom":
                        {
                            span.BaselineAlignment = BaselineAlignment.Bottom;

                            Binding fontSizeBinding = new Binding("DefaultFontSize");
                            fontSizeBinding.Source = Globals.MainWindow.DefaultFontSize;
                            fontSizeBinding.Converter = halfTextSizeConverter;

                            span.SetBinding(Span.FontSizeProperty, fontSizeBinding);
                            break;
                        }
                    default:
                        {
                            span.BaselineAlignment = BaselineAlignment.Baseline;
                            break;
                        }
                }
            }

            textBlock.Inlines.Add(span);
        }

        /// <summary>
        /// 只有在刷新大纲时才需要调用此方法。
        /// </summary>
        /// <returns></returns>
        public StackPanel BuildOutLineTextPanel()
        {
            StackPanel textPanel = new StackPanel();
            XmlNode paragraphSetNode = this.ParagraphSetNode;
            if (paragraphSetNode == null)
            {
                TextBlock tb = NewTextBlock(null);
                textPanel.Children.Add(tb);
                return textPanel;
            }

            paragraphSetNode.SetAttribute("xml:space", "preserve");//防止空格失效！

            XmlNodeList paragraphNodes = paragraphSetNode.SelectNodes(XmlTags.ParagraphTag);

            FontWeight fontWeight;
            FontStyle fontStyle = FontStyles.Normal;//全用Normal
            FontFamily fontFamily;
            double fontSize = Globals.MainWindow.DefaultFontSize;

            fontWeight = TitleManager.GetFontWeight(this.titleLevel);
            fontFamily = TitleManager.GetFontFamily(this.titleLevel);
            fontSize = TitleManager.GetFontSize(this.titleLevel);

            #region 读取标题文本

            TextBlock textBlock = NewTextBlock(null);
            textBlock.FontFamily = fontFamily;
            textBlock.FontSize = fontSize;
            //必要。否则会导致默认字号无法作用于标题文本块
            //（标题的字号是在默认字号的基础上加对应层级的值）。
            textBlock.FontStyle = fontStyle;
            textBlock.FontWeight = fontWeight;

            textPanel.Children.Add(textBlock);

            if (paragraphNodes != null && paragraphNodes.Count > 0)
            {
                for (int i = 0; i < paragraphNodes.Count; i++)
                {
                    XmlNode paragraphNode = paragraphNodes[i];

                    TextAlignment textAlignment = TextAlignment.Justify;
                    XmlAttribute attrTextAlignment = paragraphNode.GetAttribute("TextAlignment");
                    if (attrTextAlignment != null)
                    {
                        textAlignment = (TextAlignment)Enum.Parse(typeof(TextAlignment), attrTextAlignment.Value);
                    }

                    textBlock.TextAlignment = textAlignment;

                    if (i == 0)
                    {
                        //textBlock.Text = this.AutoNumberString + paragraphNode.InnerText;
                        //此处使用属性而非字段。AutoNumberString除非是T1-T５才可能返回由EditorManager刷新的
                        //自动编号。MainTitle(TopTitle）、Normal均返回string.Empty。

                        if (string.IsNullOrEmpty(this.AutoNumberString) == false)
                        {
                            Span autoNumberSpan = new Span();
                            autoNumberSpan.Inlines.Add(new Run(XmlTools.RestoreXmlChars(this.AutoNumberString)));
                            textBlock.Inlines.Add(autoNumberSpan);
                        }
                    }

                    #region 较复杂的读取方式，InnerText带意外的控制字符

                    XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
                    if (textNodes == null || textNodes.Count <= 0) continue;//一个空行。

                    foreach (XmlNode textNode in textNodes)
                    {
                        #region 读入一段文本的内容

                        //BuildOneSpan(textBlock, textNode);
                        //标题文本格式相同，且不允许上下标。

                        Run run;
                        Span span;

                        XmlAttribute attrBackColor = textNode.GetAttribute(XmlTags.BackColorTag);
                        XmlAttribute attrForeColor = textNode.GetAttribute(XmlTags.ForeColorTag);
                        if (attrBackColor != null &&
                            attrForeColor != null &&
                            attrBackColor.Value == BrushManager.GetName(BrushManager.Streamer) &&
                            attrForeColor.Value == BrushManager.GetName(BrushManager.AntiStreamer))
                        {
                            run = new Run(" " + textNode.InnerText + " ");
                            run.FontWeight = FontWeights.Bold;

                            //填空模式
                            if (fillBlankMode)
                            {
                                run.Foreground = Brushes.Transparent;
                            }
                            else
                            {
                                run.Foreground = BrushManager.GetBrush(attrForeColor.Value);
                            }

                            span = new Span(run);
                            span.Foreground = this.WidgetForeColor;
                            span.TextDecorations.Add(TextDecorations.Underline);
                        }
                        else
                        {
                            run = new Run(textNode.InnerText);

                            if (attrForeColor != null)
                            {
                                var foreColor = BrushManager.GetBrush(attrForeColor.Value);
                                if (foreColor != null) run.Foreground = foreColor;
                            }

                            if (attrBackColor != null)
                            {
                                var backColor = BrushManager.GetBrush(attrBackColor.Value);
                                if (backColor != null) run.Background = backColor;
                            }

                            span = new Span(run);
                        }

                        var attrFontStyle = textNode.GetAttribute(XmlTags.FontStyleTag);
                        if (attrFontStyle != null)
                        {
                            if (attrFontStyle.Value == "" || attrFontStyle.Value == "Normal") span.FontStyle = FontStyles.Normal;
                            else if (attrFontStyle.Value == "Italic") span.FontStyle = FontStyles.Italic;
                            else if (attrFontStyle.Value == "Oblique") span.FontStyle = FontStyles.Oblique;
                        }
                        else
                        {
                            span.FontStyle = fontStyle;
                        }

                        var attrFontWeight = textNode.GetAttribute(XmlTags.FontWeightTag);
                        if (attrFontWeight != null)
                        {
                            if (attrFontWeight.Value == "" || attrFontWeight.Value == "Normal") span.FontWeight = FontWeights.Normal;
                            else span.FontWeight = FontWeights.Bold;

                        }
                        else
                        {
                            span.FontWeight = fontWeight;
                        }

                        var attrFontSize = textNode.GetAttribute(XmlTags.FontSizeTag);
                        if (attrFontSize != null && string.IsNullOrEmpty(attrFontSize.Value) == false)
                        {
                            var fsize = double.Parse(attrFontSize.Value);
                            span.FontSize = fsize;
                        }
                        else
                        {
                            span.FontSize = fontSize;
                        }

                        var attrFontName = textNode.GetAttribute(XmlTags.FontNameTag);
                        if (attrFontName != null && string.IsNullOrEmpty(attrFontName.Value) == false)
                        {
                            FontFamily ff = new FontFamily(attrFontName.Value);
                            if (ff != null)
                                span.FontFamily = ff;
                            else span.FontFamily = fontFamily;
                        }
                        else span.FontFamily = fontFamily;

                        textBlock.Inlines.Add(span);

                        #endregion
                    }

                    #endregion

                    if (i < paragraphNodes.Count - 1)
                    {
                        textBlock = NewTextBlock(tooltipText);//实现多段读取

                        //这个方案会让人莫名其妙。2014年7月23日
                        //    textBlock.FontFamily = fontFamily;
                        //    textBlock.FontSize = fontSize;
                        //    //必要。否则会导致默认字号无法作用于标题文本块
                        //    //（标题的字号是在默认字号的基础上加对应层级的值）。
                        //    textBlock.FontStyle = fontStyle;
                        //    textBlock.FontWeight = fontWeight;

                        textPanel.Children.Add(textBlock);
                    }
                }
            }
            else
            {
                textBlock.Text = this.AutoNumberString;
            }

            #endregion

            return textPanel;
        }

        /// <summary>
        /// [静态方法]根据提供的Xml文本，创建一个新的部件。
        /// </summary>
        /// <param name="outerXml">新部件的Xml文本。</param>
        /// <returns>返回新建的部件。
        /// 如果提供的Xml节点不合要求（例如未提供“Type”特性，或“Type”特性值不受支持）返回null。</returns>
        public static Widget BuildWidget(PageEditorReader pe, XmlNode xmlData)
        {
            if (xmlData == null) return null;

            XmlAttribute attrType = xmlData.GetAttribute("Type");
            if (attrType == null) return null;

            Widget w = null;

            switch (attrType.Value)
            {
                case "BezierLine":
                    {
                        w = new BezierLineWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "Bracket":
                    {
                        w = new BracketWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "Ellipse":
                    {
                        w = new EllipseWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "Group":
                    {
                        w = new GroupWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "PictureBox":
                    {
                        w = new PictureBox(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "PolyLine":
                    {
                        w = new PolyLineWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "Rectangle":
                    {
                        w = new RectangleWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "Rhomb":
                    {
                        w = new RhombWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "StraitLine":
                    {
                        w = new StraitLineWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                case "TextArea":
                    {
                        w = new TextArea(pe);
                        w.XmlData = xmlData;//这里必须用属性。
                        break;
                    }
                case "Triangle":
                    {
                        w = new TriangleWidget(pe);
                        w.XmlData = xmlData;
                        break;
                    }
                default:
                    {
                        MessageBox.Show("　　WidgetSet类的BuildWidget()方法不支持此种部件类型：" + attrType.Value,
                            Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                        break;
                    }
            }

            return w;
        }

        /// <summary>
        /// 在没有部件实例时，取部件类型本地语言（中文）名称。
        /// </summary>
        /// <param name="widgetClassName">英文部件类名。</param>
        /// <returns>对应的中文名。</returns>
        public static string GetWidgetClassLocalName(string widgetClassName)
        {
            switch (widgetClassName)
            {
                //TODO: 添加新部件类，需要修改此处。
                case "TextArea": return "文本块";
                case "PictureBox": return "图片框";
                case "GroupWidget": return "组";             //ContentWidget

                case "StraitLineWidget": return "直线";
                case "BezierLineWidget": return "曲线";
                case "PolyLineWidget": return "折线";
                case "BracketWidget": return "括弧";         //ArrowLine

                case "EllipseWidget": return "椭圆形";
                case "RectangleWidget": return "矩形";
                case "RhombWidget": return "菱形";
                case "TriangleWidget": return "三角形";      //ShapeWidget

                default: return "未知类型部件";
            }
        }

        /// <summary>
        /// 查看是否与指定的区域存在交错。主要用于框选。
        /// </summary>
        /// <param name="rect"></param>
        /// <returns></returns>
        public virtual bool IsInRect(Rect rect)
        {
            Rect wRect = new Rect(Canvas.GetLeft(this),
                Canvas.GetTop(this), this.ActualWidth,
                this.ActualHeight);

            return wRect.IntersectsWith(rect);
        }

        void mainTextPanel_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.RefreshTextPanelLocatin();
        }

        /// <summary>
        /// 为此部件重建一个新的ID。会更新后台Xml数据（如果存在后台数据）。
        /// 只有“GroupWidget”必须重写此方法。
        /// </summary>
        public virtual void NewID()
        {
            this.id = Guid.NewGuid().ToString();
            if (this.xmlData != null)//要写后台数据的。
            {
                this.xmlData.SetAttribute(XmlTags.IdTag, this.id);
            }
        }

        /// <summary>
        /// 新建一个符合需要的TextBlock。
        /// </summary>
        /// <returns></returns>
        private TextBlock NewTextBlock(string tooltip)
        {
            TextBlock textBlock = new TextBlock()
            {
                TextWrapping = TextWrapping.Wrap,
                Foreground = widgetForeColor,
            };

            //if (this.masterEditor != null && this.masterEditor.MasterManager != null)
            //{
            //    textBlock.FontSize = this.masterEditor.MasterManager.DefaultFontSize;
            //}
            //这会导致一些意外问题：当部件内部文本字号较小时，会在顶端显示一些不需要的空白。

            textBlock.Background = Brushes.Transparent;

            if (string.IsNullOrEmpty(tooltip))
            {
                textBlock.ToolTip = null;
            }
            else
            {
                textBlock.ToolTip = tooltip;
            }

            textBlock.Cursor = Cursors.Hand;

            return textBlock;
        }

        public virtual void RefreshCommentText()
        {
            if (string.IsNullOrEmpty(this.commentText))
            {
                this.commentAdorner.ToolTip = null;
                this.commentAdorner.Visibility = System.Windows.Visibility.Collapsed;
            }
            else
            {
                this.commentAdorner.ToolTip = this.WidgetClassLocalName + " ◆ 备注： " + this.commentText;
                this.commentAdorner.Visibility = System.Windows.Visibility.Visible;
            }
        }

        public virtual void RefreshHyperLinkText()
        {
            if (string.IsNullOrEmpty(this.hyperLinkText))
            {
                this.hyperLinkAdorner.ToolTip = null;
                this.hyperLinkAdorner.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.hyperLinkAdorner.ToolTip =
                    this.WidgetClassLocalName + " ◆ 链接到： " + this.hyperLinkText;
                this.hyperLinkAdorner.Visibility = Visibility.Visible;
            }
        }

        /// <summary>
        /// ★注意：此方法在内部会先调用RefreshText()方法。
        /// 当EditorManager的DefaultFontSize刷新时，如果部件使用了此字号，则应进行相应刷新。
        /// 例如：矩形部件的“标记文本”即使用了此字号。
        /// </summary>
        public virtual void RefreshDefaultFontSize()
        {
            this.RefreshText();
        }

        /// <summary>
        /// 刷新此部件在页面中的层次。
        /// </summary>
        public virtual void RefreshLayerIndex()
        {
            Canvas.SetZIndex(this, (int)layerIndex);
        }

        /// <summary>
        /// Location设置好后，刷新部件位置。
        /// </summary>
        public abstract void RefreshLocation();

        /// <summary>
        /// 刷新阴影效果。
        /// </summary>
        public abstract void RefreshIsShadowVisible();

        /// <summary>
        /// 根据XmlData中的ParagraphSet中的文本内容来生成TextBlock的内容。
        /// 2012年6月24日添加了对TitleLevel的支持。
        /// </summary>
        public virtual void RefreshText()
        {
            if (this.masterEditor == null) return;

            if (xmlData == null || this.mainTextPanel == null) return;

            this.mainTextPanel.Children.Clear();

            XmlNode paragraphSetNode = this.ParagraphSetNode;
            if (paragraphSetNode == null)
            {
                TextBlock tb = NewTextBlock(tooltipText);
                this.mainTextPanel.Children.Add(tb);
                return;
            }

            paragraphSetNode.SetAttribute("xml:space", "preserve");//防止空格失效！

            XmlNodeList paragraphNodes = paragraphSetNode.SelectNodes(XmlTags.ParagraphTag);

            FontWeight fontWeight;
            FontStyle fontStyle = FontStyles.Normal;//全用Normal
            FontFamily fontFamily;
            double fontSize = Globals.MainWindow.DefaultFontSize;

            switch (this.titleLevel)
            {
                case TitleStyle.Normal:
                    {
                        #region 读取并呈现非标题部件文本

                        if (paragraphNodes == null || paragraphNodes.Count <= 0)
                        {
                            TextBlock textBlock = NewTextBlock(tooltipText);
                            this.mainTextPanel.Children.Add(textBlock);
                        }
                        else
                        {
                            for (int i = 0; i < paragraphNodes.Count; i++)
                            {
                                XmlNode paragraphNode = paragraphNodes[i];

                                TextAlignment textAlignment = TextAlignment.Justify;
                                XmlAttribute attrTextAlignment = paragraphNode.GetAttribute("TextAlignment");
                                if (attrTextAlignment != null)
                                {
                                    textAlignment = (TextAlignment)Enum.Parse(typeof(TextAlignment), attrTextAlignment.Value);
                                }

                                TextBlock textBlock = NewTextBlock(tooltipText);
                                textBlock.TextAlignment = textAlignment;

                                if (i == 0)
                                {
                                    Span autoNumberSpan = new Span();
                                    autoNumberSpan.Inlines.Add(new Run(this.AutoNumberString));
                                    textBlock.Inlines.Add(autoNumberSpan);
                                }

                                XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
                                if (textNodes != null && textNodes.Count > 0)
                                {
                                    foreach (XmlNode textNode in textNodes)
                                    {
                                        #region 读入一段文本的内容

                                        BuildAndAppendOneSpan(textBlock, textNode);

                                        #endregion
                                    }
                                }

                                this.mainTextPanel.Children.Add(textBlock);//空段也要添加的。
                            }
                        }
                        #endregion

                        break;
                    }
                default:
                    {
                        fontWeight = TitleManager.GetFontWeight(this.titleLevel);
                        fontFamily = TitleManager.GetFontFamily(this.titleLevel);
                        fontSize = TitleManager.GetFontSize(this.titleLevel);

                        #region 读取标题文本

                        TextBlock textBlock = NewTextBlock(tooltipText);
                        textBlock.FontFamily = fontFamily;
                        textBlock.FontSize = fontSize;
                        //必要。否则会导致默认字号无法作用于标题文本块
                        //（标题的字号是在默认字号的基础上加对应层级的值）。
                        textBlock.FontStyle = fontStyle;
                        textBlock.FontWeight = fontWeight;

                        this.mainTextPanel.Children.Add(textBlock);

                        if (paragraphNodes != null && paragraphNodes.Count > 0)
                        {
                            for (int i = 0; i < paragraphNodes.Count; i++)
                            {
                                XmlNode paragraphNode = paragraphNodes[i];

                                TextAlignment textAlignment = TextAlignment.Justify;
                                XmlAttribute attrTextAlignment = paragraphNode.GetAttribute("TextAlignment");
                                if (attrTextAlignment != null)
                                {
                                    textAlignment = (TextAlignment)Enum.Parse(typeof(TextAlignment), attrTextAlignment.Value);
                                }

                                textBlock.TextAlignment = textAlignment;

                                if (i == 0)
                                {
                                    //textBlock.Text = this.AutoNumberString + paragraphNode.InnerText;
                                    //此处使用属性而非字段。AutoNumberString除非是T1-T５才可能返回由EditorManager刷新的
                                    //自动编号。MainTitle(TopTitle）、Normal均返回string.Empty。

                                    if (string.IsNullOrEmpty(this.AutoNumberString) == false)
                                    {
                                        Span autoNumberSpan = new Span();
                                        autoNumberSpan.Inlines.Add(new Run(XmlTools.RestoreXmlChars(this.AutoNumberString)));
                                        textBlock.Inlines.Add(autoNumberSpan);
                                    }
                                }

                                #region 较复杂的读取方式，InnerText带意外的控制字符

                                XmlNodeList textNodes = paragraphNode.SelectNodes(XmlTags.TextTag);
                                if (textNodes != null && textNodes.Count > 0)
                                {
                                    foreach (XmlNode textNode in textNodes)
                                    {
                                        #region 读入一段文本的内容

                                        //BuildOneSpan(textBlock, textNode);
                                        //标题文本格式相同，且不允许上下标。

                                        Run run;
                                        Span span;

                                        XmlAttribute attrBackColor = textNode.GetAttribute(XmlTags.BackColorTag);
                                        XmlAttribute attrForeColor = textNode.GetAttribute(XmlTags.ForeColorTag);
                                        if (attrBackColor != null &&
                                            attrForeColor != null &&
                                            attrBackColor.Value == BrushManager.GetName(BrushManager.Streamer) &&
                                            attrForeColor.Value == BrushManager.GetName(BrushManager.AntiStreamer))
                                        {
                                            run = new Run(" " + textNode.InnerText + " ");
                                            run.FontWeight = FontWeights.Bold;

                                            //填空模式
                                            if (fillBlankMode)
                                            {
                                                run.Foreground = Brushes.Transparent;
                                            }

                                            span = new Span(run);
                                            span.Foreground = this.widgetForeColor;
                                            span.TextDecorations.Add(TextDecorations.Underline);
                                        }
                                        else
                                        {
                                            run = new Run(textNode.InnerText);

                                            if (attrForeColor != null)
                                            {
                                                var foreColor = BrushManager.GetBrush(attrForeColor.Value);
                                                if (foreColor != null) run.Foreground = foreColor;
                                            }

                                            if (attrBackColor != null)
                                            {
                                                var backColor = BrushManager.GetBrush(attrBackColor.Value);
                                                if (backColor != null) run.Background = backColor;
                                            }

                                            span = new Span(run);
                                        }

                                        var attrFontStyle = textNode.GetAttribute(XmlTags.FontStyleTag);
                                        if (attrFontStyle != null)
                                        {
                                            if (attrFontStyle.Value == "" || attrFontStyle.Value == "Normal") span.FontStyle = FontStyles.Normal;
                                            else if (attrFontStyle.Value == "Italic") span.FontStyle = FontStyles.Italic;
                                            else if (attrFontStyle.Value == "Oblique") span.FontStyle = FontStyles.Oblique;
                                        }
                                        else
                                        {
                                            span.FontStyle = fontStyle;
                                        }

                                        var attrFontWeight = textNode.GetAttribute(XmlTags.FontWeightTag);
                                        if (attrFontWeight != null)
                                        {
                                            if (attrFontWeight.Value == "" || attrFontWeight.Value == "Normal") span.FontWeight = FontWeights.Normal;
                                            else span.FontWeight = FontWeights.Bold;

                                        }
                                        else
                                        {
                                            span.FontWeight = fontWeight;
                                        }

                                        var attrFontSize = textNode.GetAttribute(XmlTags.FontSizeTag);
                                        if (attrFontSize != null && string.IsNullOrEmpty(attrFontSize.Value) == false)
                                        {
                                            var fsize = double.Parse(attrFontSize.Value);
                                            span.FontSize = fsize;
                                        }
                                        else
                                        {
                                            span.FontSize = fontSize;
                                        }

                                        var attrFontName = textNode.GetAttribute(XmlTags.FontNameTag);
                                        if (attrFontName != null && string.IsNullOrEmpty(attrFontName.Value) == false)
                                        {
                                            FontFamily ff = new FontFamily(attrFontName.Value);
                                            if (ff != null)
                                                span.FontFamily = ff;
                                            else span.FontFamily = fontFamily;
                                        }
                                        else span.FontFamily = fontFamily;

                                        textBlock.Inlines.Add(span);

                                        #endregion
                                    }
                                }

                                #endregion

                                if (i < paragraphNodes.Count - 1)
                                {
                                    textBlock = NewTextBlock(tooltipText);//实现多段读取

                                    //这样处理会让人无法理解标题中格式为何不起作用。2014年7月23日。
                                    //textBlock.FontFamily = fontFamily;
                                    //textBlock.FontSize = fontSize;
                                    //必要。否则会导致默认字号无法作用于标题文本块
                                    //（标题的字号是在默认字号的基础上加对应层级的值）。
                                    //textBlock.FontStyle = fontStyle;


                                    this.mainTextPanel.Children.Add(textBlock);
                                }
                            }
                        }
                        else
                        {
                            textBlock.Text = this.AutoNumberString;
                        }

                        #endregion

                        break;
                    }
            }

            //要注意刷新mainTextStackPanel的位置。
        }

        public abstract void RefreshTextPanelLocatin();

        public virtual void RefreshIsTextVisible()
        {
            if (this.isTextVisible)
            {
                this.mainTextPanel.Visibility = Visibility.Visible;
                this.textHideAdorner.Visibility = Visibility.Collapsed;
            }
            else
            {
                this.mainTextPanel.Visibility = Visibility.Hidden;//不能用折叠。
                this.textHideAdorner.Visibility = Visibility.Visible;
            }
        }

        /// <summary>
        /// WidgetBackground属性值改变时会调用此方法刷新部件的背景色。
        /// ——亦可根据需要调用。
        /// </summary>
        public abstract void RefreshWidgetBackColor();

        /// <summary>
        /// WidgetForeground属性值改变时会调用此方法刷新部件的前景色。
        /// </summary>
        public virtual void RefreshWidgetForeColor()
        {
            foreach (UIElement ue in this.mainTextPanel.Children)
            {
                TextBlock tb = ue as TextBlock;
                if (tb == null) continue;

                tb.Foreground = widgetForeColor;
                foreach (Inline inline in tb.Inlines)
                {
                    Span span = inline as Span;
                    if (span == null) continue;

                    span.Foreground = widgetForeColor;
                }
            }
        }

        /// <summary>
        /// WidgetLineColor属性值改变时会调用此方法刷新部件的前景色。
        /// </summary>
        public abstract void RefreshWidgetLineColor();

        /// <summary>
        /// 刷新线宽。
        /// </summary>
        public abstract void RefreshWidgetLineWidth();

        /// <summary>
        /// 根据提供的属性名和值来设置对应属性的值。
        /// 
        /// 此方法只处理\Enums\LunarPropertyDataType.cs中的“PropertyDateType”枚举定义的几种数据类型。
        /// </summary>
        /// <param name="aliasName">属性名。</param>
        /// <param name="value">属性值。</param>
        public virtual void SetProperty(string propertyName, string value)
        {
            if (propertyName == null || propertyName.Length <= 0)
                throw new ArgumentNullException("Widget.SetProperty()方法的“propertyName”不能为null或空字符串。");

            if (value == null)
                throw new ArgumentNullException("Widget.SetProperty()方法的“value”不能为null。");

            // 利用反射来实现——这样就几乎没有必要再考虑在派生类中重写此一方法了！！！
            try
            {
                PropertyInfo[] propertyInfoArray = GetType().GetProperties();
                foreach (PropertyInfo propertyInfo in propertyInfoArray)
                {
                    if (propertyInfo.CanWrite == false) continue;

                    LunarPropertyAttribute lpa = (LunarPropertyAttribute)Attribute.
                        GetCustomAttribute(propertyInfo, typeof(LunarPropertyAttribute));

                    if (lpa == null || lpa.PropertyName != propertyName) continue;

                    switch (lpa.PropertyType)
                    {
                        case Enums.PropertyDateType.Bool:
                            {
                                propertyInfo.SetValue(this, bool.Parse(value), null);
                                break;
                            }
                        case Enums.PropertyDateType.Brush:
                            {
                                propertyInfo.SetValue(this,
                                    BrushManager.GetBrushByEnglishName(value), null);
                                break;
                            }
                        case PropertyDateType.Dock:
                            {
                                propertyInfo.SetValue(this, (Dock)Enum.Parse(typeof(Dock), value), null);
                                break;
                            }
                        case Enums.PropertyDateType.Double:
                            {
                                propertyInfo.SetValue(this,
                                   double.Parse(value), null); break;
                            }
                        case Enums.PropertyDateType.String:
                            {
                                propertyInfo.SetValue(this, value, null); break;
                            }
                        case PropertyDateType.ParagraphSetInnerXmlText:
                            {
                                XmlNode paragraphSetNode = this.xmlData.SelectSingleNode(XmlTags.ParagraphSetTag);
                                if (paragraphSetNode != null)
                                {
                                    propertyInfo.SetValue(this, value, null);
                                }
                                break;
                            }
                        case PropertyDateType.Orientation:
                            {
                                propertyInfo.SetValue(this, (Orientation)Enum.Parse(typeof(Orientation), value), null);
                                break;
                            }
                        case Enums.PropertyDateType.OutXmlText:
                            {
                                propertyInfo.SetValue(this, XmlTools.ReplaceOutXmlText(this.xmlData, value), null); break;
                            }
                        case PropertyDateType.Point:
                            {
                                propertyInfo.SetValue(this,
                                    Point.Parse(value), null); break;
                            }
                        case PropertyDateType.DashType:
                            {
                                propertyInfo.SetValue(this, (LineDashType.DashType)
                                    Enum.Parse(typeof(LineDashType.DashType), value), null);
                                break;
                            }
                        case PropertyDateType.ArrowType:
                            {
                                propertyInfo.SetValue(this, (ArrowType)Enum.Parse(typeof(ArrowType), value), null);
                                break;
                            }
                        case PropertyDateType.MaskType:
                            {
                                propertyInfo.SetValue(this, (MaskType)Enum.Parse(typeof(MaskType), value), null);
                                break;
                            }
                        case PropertyDateType.LayerIndex:
                            {
                                propertyInfo.SetValue(this, (WidgetLayerIndex)Enum.Parse(typeof(WidgetLayerIndex), value), null);
                                break;
                            }
                        case PropertyDateType.Thickness:
                            {
                                propertyInfo.SetValue(this, (Thickness)masterEditor.ThickConverter.ConvertFromString(value), null);
                                break;
                            }
                        case PropertyDateType.TitleStyle:
                            {
                                propertyInfo.SetValue(this, (Enums.TitleStyle)Enum.Parse(typeof(Enums.TitleStyle), value), null);
                                break;
                            }
                        case PropertyDateType.WidgetForm:
                            {
                                propertyInfo.SetValue(this, (Enums.WidgetForm)Enum.Parse(typeof(Enums.WidgetForm), value), null);
                                break;
                            }
                        case PropertyDateType.PolyLineForm:
                            {
                                propertyInfo.SetValue(this, (Enums.PolyLineForms)Enum.Parse(typeof(Enums.PolyLineForms), value), null);
                                break;
                            }
                        case PropertyDateType.BezierLineForms://曲线、折线独有的也放这里，是为了免除在子类中再加try/catch块。
                            {
                                propertyInfo.SetValue(this, (Enums.BezierLineForms)Enum.Parse(typeof(Enums.BezierLineForms), value), null);
                                break;
                            }
                        case PropertyDateType.TextAreaAlignment:
                            {
                                propertyInfo.SetValue(this, (Enums.TextAreaAlignment)Enum.Parse(typeof(Enums.TextAreaAlignment), value), null);
                                break;
                            }
                        case PropertyDateType.OuterBorderType:
                            {
                                propertyInfo.SetValue(this, (Enums.OuterBorderType)Enum.Parse(typeof(Enums.OuterBorderType), value), null);
                                break;
                            }
                        case PropertyDateType.TriangleForm:
                            {
                                propertyInfo.SetValue(this, (Enums.TriangleForm)Enum.Parse(typeof(Enums.TriangleForm), value), null);
                                break;
                            }
                        case PropertyDateType.LinkToPoint:
                            {
                                propertyInfo.SetValue(this, (Enums.LinkToPoint)Enum.Parse(typeof(Enums.LinkToPoint), value), null);
                                break;
                            }
                        case PropertyDateType.BracketLineForm:
                            {
                                propertyInfo.SetValue(this, (Enums.BracketLineForms)Enum.Parse(typeof(Enums.BracketLineForms), value), null);
                                break;
                            }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("　　设置部件属性值时出现错误。异常信息如下：\r\n" + ex.Message + "\r\n" + ex.StackTrace,
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
        }

        #endregion

        #region 事件=========================================================================================================



        #endregion

        #region INotifyPropertyChanged 成员

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(object sender,
           PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(sender, e);
            }
        }

        #endregion

    }
}
